﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace IoTPowerExample
{
    internal class Device
    {

        public event EventHandler<object> InitialReceived;
        public event EventHandler<(double,double)[]> DataReceived;

        //usb设备？串口设备？
        private bool Is_USB = false;

        /// <summary>
        /// 连接设备
        /// </summary>
        /// <param name="name">串口名，可为空</param>
        /// <returns>是否成功连接</returns>
        public bool Connect(string name)
        {
            try
            {
                if (name.StartsWith("[") && name.EndsWith("]"))
                {
                    Is_USB = true;
                    var nameBuff = Encoding.UTF8.GetBytes(name.Substring(1, name.Length - 2));
                    if (iot_uart_open_usb(nameBuff, (uint)nameBuff.Length) == 1)
                    {
                        new Thread(Serial_DataReceived).Start();//循环读数据
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    int n = int.Parse(name.Substring(3, name.Length - 3));
                    if (iot_uart_open(n) == 1)
                    {
                        new Thread(Serial_DataReceived).Start();//循环读数据
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"uart connect failed:{e}",Color.Red);
                return false;
            }
        }

        //接收到事件
        private void Serial_DataReceived()
        {
            while (true)
            {
                byte r = 0;
                try
                {
                    r = iot_parse();
                }
                catch (Exception e)
                {
                    Console.WriteLine($"uart pause error:{e}", Color.Red);
                }

                switch (r)
                {
                    case 0://数据还没来
                        continue;
                    case 255://串口被关了，不读了
                        return;
                }
                Parse(r);
            }
        }

        /// <summary>
        /// 尝试解析数据
        /// </summary>
        /// <returns>长度够吗</returns>
        public void Parse(byte pr)
        {
            switch (pr)
            {
                case 0x04://设置的各种信息数据
                    InitialReceived?.Invoke(null, null);
                    break;
                case 0x01://整包数据
                    var packLen = iot_get_class() switch
                    {
                        4 => 800,//cc
                        _ => 16,//power
                    };
                    var data = new (double, double)[packLen];
                    for(int i=0; i<packLen;i++)
                        data[i] = (iot_get_current(i), iot_get_voltage(i));
                    DataReceived?.Invoke(null, data);
                    break;
                case 0x00://结束了，不算错
                    break;
                case 0xff://结束了，不算错
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 获取设备列表
        /// </summary>
        /// <returns>设备列表，带[]的为USB设备</returns>
        public static List<string> GetList()
        {

            List<string> ports = new List<string>(SerialPort.GetPortNames());
            
            using (var d = iot_usb_get_devices())
            {
                var ds = d.AsString();
                if (ds.Length > 0)
                {
                    var l = ds.Split(',');
                    foreach (string s in l)
                        ports.Add($"[{s}]");
                }
            }
            return ports;
        }


        //-------------------------下面都是dll里的声明--------------------------------//
        [DllImport("iot_parser.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern BytesHandle iot_usb_get_devices();
        [DllImport("iot_parser.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern byte iot_uart_open_usb(byte[] ptr, uint len);
        [DllImport("iot_parser.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern byte iot_uart_open(int com);
        [DllImport("iot_parser.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern byte iot_parse();
        [DllImport("iot_parser.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern byte iot_get_class(); 
        [DllImport("iot_parser.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern double iot_get_current(int i);
        [DllImport("iot_parser.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern double iot_get_voltage(int i);
        [DllImport("iot_parser.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void iot_uart_send_initial();
    }

    internal class BytesHandle : SafeHandle
    {
        public BytesHandle() : base(IntPtr.Zero, true) { }
        public override bool IsInvalid
        {
            get { return false; }
        }

        /// <summary>
        /// 将返回的结果当作字符串来读取
        /// </summary>
        /// <returns>读到的字节数组</returns>
        public string AsString()
        {
            //当前的指针位置
            var ptr = handle;
            //读到的数据，缓存
            List<byte> temp = new List<byte>();
            while (true)
            {
                //读一字节数据
                var c = Marshal.ReadByte(ptr);
                //不为0则表示字符串还没结束
                if (c != 0)
                    temp.Add(c);
                else//说明字符串结束了
                    break;
                ptr += 1;//指针向后挪1字节
            }
            return Encoding.Default.GetString(temp.ToArray());
        }

        /// <summary>
        /// 将返回的结果当作byte数组来读取
        /// </summary>
        /// <param name="len">读取的长度</param>
        /// <returns>读到的字节数组</returns>
        public byte[] AsBytes(byte len)
        {
            byte[] buffer = new byte[len];
            Marshal.Copy(handle, buffer, 0, buffer.Length);
            return buffer;
        }

        [DllImport("iot_parser.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void free_s(IntPtr str);
        /// <summary>
        /// 调用dll中的free接口，释放资源
        /// </summary>
        protected override bool ReleaseHandle()
        {
            free_s(handle);
            return true;
        }
    }
}
